package com.hx.yupao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hx.yupao.common.ErrorCode;
import com.hx.yupao.exception.BusinessException;
import com.hx.yupao.mapper.UserTeamMapper;
import com.hx.yupao.model.domain.Team;
import com.hx.yupao.mapper.TeamMapper;
import com.hx.yupao.model.domain.User;
import com.hx.yupao.model.domain.UserTeam;
import com.hx.yupao.model.dto.TeamQuery;
import com.hx.yupao.model.enums.TeamStatusEnum;
import com.hx.yupao.model.request.TeamJoinRequest;
import com.hx.yupao.model.request.TeamQuitRequest;
import com.hx.yupao.model.request.TeamUpdateRequest;
import com.hx.yupao.model.vo.TeamUserVO;
import com.hx.yupao.model.vo.UserVO;
import com.hx.yupao.service.TeamService;
import com.hx.yupao.service.UserService;
import com.hx.yupao.service.UserTeamService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author Lenovo
 * @description 针对表【team(队伍)】的数据库操作Service实现
 * @createDate 2025-10-02 15:58:36
 */
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService {

    private static final int SELECT_TEAM_STATUS = 3;
    @Resource
    private RedissonClient redissonClient;

    @Resource
    private UserTeamService userTeamService;

    @Resource
    private UserTeamMapper userTeamMapper;

    @Resource
    private UserService userService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public long addTeam(Team team, User loginUser) {
        //1. 请求参数是否为空?
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2. 是否登录，未登录不允许创建
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        final long userId = loginUser.getId();
        //3. 校验信息
        //   1.队伍人数>1且<=20
        int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);
        if (maxNum < 1 || maxNum > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不满足要求");
        }
        //   2.队伍标题 <= 20
        String name = team.getName();
        if (StringUtils.isBlank(name) || name.length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不满足要求");
        }
        //   3.描述<= 512
        String description = team.getDescription();
        if (StringUtils.isBlank(description) || description.length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "描述不满足要求");
        }
        //   4.status 是否公开(int)不传默认为0(公开)
        int teamStatus = Optional.ofNullable(team.getTeamStatus()).orElse(0);
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(teamStatus);
        if (statusEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求");
        }
        //   5.如果 status 是加密状态，一定要有密码，且密码<=32
        String password = team.getPassword();
        if (TeamStatusEnum.SECRET.equals(statusEnum)) {
            if (StringUtils.isBlank(password) || password.length() >= 32) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码设置不正确");
            }
        }
        //   6.超时时间>当前时间
        Date expireTime = team.getExpireTime();
        if (expireTime != null && new Date().after(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "超时时间设置不正确");
        }
        //   7.校验用户最多创建5个队伍
        //todo 有bug，点的足够快可能同时创建100个队伍，可以加sychronized或者分布式锁
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", userId);
        long hasTeamNum = this.count(queryWrapper);
        if (hasTeamNum >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户最多创建5个队伍");
        }
        //8. 插入队伍信息到队伍表
        team.setId(null);
        team.setUserId(userId);
        boolean result = this.save(team);
        if (!result) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍表失败");
        }
        //9. 插入用户=>队伍关系到关系表
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(team.getId());
        userTeam.setJoinTime(new Date());
        result = userTeamService.save(userTeam);
        if (!result) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");
        }
        return team.getId();
    }

    @Override
    public List<TeamUserVO> listTeams(TeamQuery teamQuery, boolean isAdmin) {
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        //组合查询条件
        if (teamQuery != null) {
            Long id = teamQuery.getId();
            if (id != null && id > 0) {
                queryWrapper.eq("id", id);
            }
            String searchText = teamQuery.getSearchText();
            if (StringUtils.isNotBlank(searchText)) {
                queryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
            }
            Long userId = teamQuery.getUserId();
            if (userId != null && userId > 0) {
                queryWrapper.eq("userId", userId);
            }
            String description = teamQuery.getDescription();
            if (description != null) {
                queryWrapper.like("description", description);
            }
            Integer maxNum = teamQuery.getMaxNum();
            if (maxNum != null && maxNum > 0) {
                queryWrapper.eq("maxNum", maxNum);
            }
            //根据查询条件查询
            Integer teamStatus = teamQuery.getTeamStatus();
            TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(teamStatus);
            if (!isAdmin){
                if (teamStatus == null) {
                    statusEnum = TeamStatusEnum.PUBLIC;
                }
                if (teamStatus == SELECT_TEAM_STATUS){
                    //查询加密和公开的
                    queryWrapper.in("teamStatus", TeamStatusEnum.PUBLIC.getValue(), TeamStatusEnum.SECRET.getValue());
                } else {
                    //只查询对应状态的
                    queryWrapper.eq("teamStatus", statusEnum.getValue());
                }
            }
            if (!isAdmin && statusEnum.equals(TeamStatusEnum.PRIVATE)) {
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
            String name = teamQuery.getName();
            if (StringUtils.isNotBlank(name)) {
                queryWrapper.like("name", name);
            }
        }
        //不展示已过期的队伍
        //expireTime is null or expireTime > now()
        if (!isAdmin){
            queryWrapper.and(qw -> qw.gt("expireTime", new Date()).or().isNull("expireTime"));
        }

        List<Team> teamList = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(teamList)) {
            return new ArrayList<>();
        }
        //关联查询队伍成员关系
        //sql实现
//        List<TeamUserVO> teamUserVOList = new ArrayList<>();
//        for (Team team : teamList) {
//            Long id = team.getId();
//            List<UserVO> userList = userTeamMapper.getUsersByTeamId(id);
//            TeamUserVO teamUserVO = new TeamUserVO();
//            BeanUtils.copyProperties(team, teamUserVO);
//            teamUserVO.setUserList(userList);
//            teamUserVOList.add(teamUserVO);
//        }
        //关联创建人信息
        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        for (Team team : teamList) {
            User organizer = userService.getById(team.getUserId());
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team, teamUserVO);
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(organizer, userVO);
            teamUserVO.setUser(userVO);
            teamUserVOList.add(teamUserVO);
        }

        return teamUserVOList;
    }

    @Override
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest, User loginUser) {
        if (teamUpdateRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = teamUpdateRequest.getId();
        if (id == null || id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team oldTeam = this.getById(id);
        if (oldTeam == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在");
        }
        //只有管理员和队伍的创建者才能修改
        if (oldTeam.getUserId() != loginUser.getId() && !userService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        TeamStatusEnum enumByValue = TeamStatusEnum.getEnumByValue(teamUpdateRequest.getTeamStatus());
        if (enumByValue.equals(TeamStatusEnum.SECRET)) {
            if (StringUtils.isBlank(teamUpdateRequest.getPassword())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "加密房间必须设置密码");
            }
        }
        Team team = new Team();
        BeanUtils.copyProperties(teamUpdateRequest, team);
        boolean result = this.updateById(team);
        return result;
    }

    @Override
    public boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {
        if (teamJoinRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long teamId = teamJoinRequest.getTeamId();
        if (teamId == null || teamId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = this.getById(teamId);
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }
        Date expireTime = team.getExpireTime();
        if (expireTime != null && expireTime.before(new Date())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍已过期");
        }

        //禁止加入私有的队伍
        TeamStatusEnum enumByValue = TeamStatusEnum.getEnumByValue(team.getTeamStatus());
        if (TeamStatusEnum.PRIVATE.equals(enumByValue)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "禁止加入私有队伍");
        }
        String password = teamJoinRequest.getPassword();
        if (TeamStatusEnum.SECRET.equals(enumByValue)) {
            if (StringUtils.isBlank(password) || !team.getPassword().equals(password)) {
                throw new BusinessException(ErrorCode.NULL_ERROR, "密码错误");
            }
        }

        long loginUserId = loginUser.getId();

        //分布式锁
//        RLock lock = redissonClient.getLock(REDIS_JOIN_TEAM_KEY);
//        try {
//            while (true) {
//                if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
//                    //该用户已加入队伍数量
//                    QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
//                    queryWrapper.eq("userId", loginUserId);
//                    long count = userTeamService.count(queryWrapper);
//                    if (count >= 5) {
//                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多加入5个队伍");
//                    }
//
//                    //不能重复加入已加入的队伍
//                    queryWrapper = new QueryWrapper<>();
//                    queryWrapper.eq("teamId", teamId);
//                    queryWrapper.eq("userId", loginUserId);
//                    long hasUserJoinTeam = userTeamService.count(queryWrapper);
//                    if (hasUserJoinTeam > 0) {
//                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户已加入该队伍");
//                    }
//
//                    //已加入队伍的人数
//                    long teamHasJoinNum = this.countTeamUserByTeamId(teamId);
//                    if (teamHasJoinNum >= team.getMaxNum()) {
//                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数已满");
//                    }
//
//                    UserTeam userTeam = new UserTeam();
//                    userTeam.setUserId(loginUserId);
//                    userTeam.setTeamId(teamId);
//                    userTeam.setJoinTime(new Date());
//                    boolean saveResult = userTeamService.save(userTeam);
//
//                    if (!saveResult) {
//                        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "加入队伍失败");
//                    }
//                    return saveResult;
//
//                }
//            }
//        } catch (InterruptedException e) {
//            log.error("发生错误", e);
//            return false;
//        } finally {
//            //只能释放自己的锁，放在finally防止前面出错中断，执行不到释放锁的代码
//            if (lock.isHeldByCurrentThread()) {
//                lock.unlock();
//                System.out.println("unlock" + Thread.currentThread().getId());
//            }
//        }

        //单机锁
        long userId = loginUser.getId();
        synchronized (String.valueOf(userId).intern()) {
            //该用户已加入队伍数量
            QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", loginUserId);
            long count = userTeamService.count(queryWrapper);
            if (count >= 5) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多加入5个队伍");
            }

            //不能重复加入已加入的队伍
            queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("teamId", teamId);
            queryWrapper.eq("userId", loginUserId);
            long hasUserJoinTeam = userTeamService.count(queryWrapper);
            if (hasUserJoinTeam > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户已加入该队伍");
            }
            //已加入队伍的人数
            long teamHasJoinNum = this.countTeamUserByTeamId(teamId);
            if (teamHasJoinNum >= team.getMaxNum()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数已满");
            }

            UserTeam userTeam = new UserTeam();
            userTeam.setUserId(loginUserId);
            userTeam.setTeamId(teamId);
            userTeam.setJoinTime(new Date());
            boolean saveResult = userTeamService.save(userTeam);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "加入队伍失败");
            }
            return saveResult;
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {
        if (teamQuitRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = teamQuitRequest.getTeamId();

        Team team = getTeamById(teamId);
        
        long userId = loginUser.getId();
        UserTeam queryUserTeam = new UserTeam();
        queryUserTeam.setTeamId(teamId);
        queryUserTeam.setUserId(userId);
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>(queryUserTeam);
        long count = userTeamService.count(queryWrapper);
        if (count == 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "未加入队伍");
        }
        long teamHasJoinNum = this.countTeamUserByTeamId(teamId);
        if (teamHasJoinNum == 1){
            //删除队伍
            this.removeById(teamId);
        } else {
            //判断是否是队长
            if (team.getUserId() == userId){
                //把队伍转移给最早加入的用户
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("teamId", teamId);
                userTeamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if (CollectionUtils.isEmpty(userTeamList) || userTeamList.size() <= 1){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                UserTeam nextUserTeam = userTeamList.get(1);
                Long nextTeamLeaderId = nextUserTeam.getUserId();
                Team updateTeam = new Team();
                updateTeam.setUserId(nextTeamLeaderId);
                updateTeam.setId(teamId);
                boolean update = this.updateById(updateTeam);
                if (!update){
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "更新队长失败");
                }
            }
        }
        //移除关系
        return userTeamService.remove(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTeam(long id, User loginUser) {
        //1. 校验请求参数
        if (id <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2. 校验队伍是否存在
        Team team = getTeamById(id);
        //3. 校验你是不是队伍的队长
        if (team.getUserId() != loginUser.getId()){
            throw new BusinessException(ErrorCode.NO_AUTH, "禁止操作");
        }
        //4. 移除所有加入队伍关联信息
        //移除关系
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", id);
        boolean remove = userTeamService.remove(userTeamQueryWrapper);
        if (!remove){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除队伍关联信息失败");
        }
        //5. 删除队伍
        boolean result = this.removeById(id);
        return result;
    }

    /**
     * 根据队伍id查询队伍
     * @param teamId
     * @return
     */
    private Team getTeamById(Long teamId) {
        if (teamId == null || teamId <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = this.getById(teamId);
        if (team == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }
        return team;
    }


    /**
     * 获取某队伍当前人数
     * @param teamId
     * @return
     */
    private long countTeamUserByTeamId(long teamId){
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId", teamId);
        long count = userTeamService.count(queryWrapper);
        return count;
    }

}




